package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.Constants.RedisConstants;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.mq.message.SignInMessage;
import com.tianji.learning.service.IPointsRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-04-15
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {

    private final StringRedisTemplate redisTemplate;
    @Override
    public void saveRecord(SignInMessage message, PointsRecordType type) {
        log.info("保存积分记录：{}", message);
        log.info("保存积分的类型：{}", type);
       switch (type){
           case SIGN:
               //签到
               Sign(message,type);
               break;
           case LEARNING:
               //学习
               Learning(message,type);
               break;
           case QA:
               //问答
               QuestionAndAnswer(message,type);
               break;
           case NOTE:
               //笔记
               Note(message,type);
               break;
           case COMMENT:
               //评论
               Comment(message,type);
               break;
           default:
               log.error("不支持的积分类型：{}", type);
               break;
       }
    }

    @Override
    public List<PointsStatisticsVO> queryTodayPoints() {
        //1.获取当前登录用户id
        Long userId = UserContext.getUser();
        //2.获取当前时间
        LocalDateTime now = LocalDateTime.now();
        //3.获取当天起始时间和结束时间
        LocalDateTime startTime = now.withHour(0).withMinute(0).withSecond(0);
        LocalDateTime endTime = now.withHour(23).withMinute(59).withSecond(59);
        //select type,sum(points) as points from points_record where user_id=? and type=? and create_time between ? and ? groupBy type
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        wrapper.select("type,sum(points) as points")
                .eq("user_id", userId)
                .between("create_time", startTime, endTime)
                .groupBy("type");
        List<PointsRecord> list = this.list(wrapper);
        if (CollUtils.isEmpty(list)){
            log.info("用户{}今天没有积分记录", list);
            return CollUtils.emptyList();
        }
        ArrayList<PointsStatisticsVO> vos = new ArrayList<>(list.size());
        for (PointsRecord record : list) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setPoints(record.getPoints());
            vo.setType(record.getType().getDesc());
            vo.setMaxPoints(record.getType().getMaxPoints());
            vos.add(vo);
        }
        log.info("用户{}今天积分记录：{}", userId, vos);
        return vos;
    }


    private void Comment(SignInMessage message, PointsRecordType type) {
        this.save(new PointsRecord().setPoints(message.getPoints()).setUserId(message.getUserId()).setType(type));
        saveScoreToRedis(message);
    }

    private void saveScoreToRedis(SignInMessage message) {
        // 1.获取当前时间
        LocalDateTime now = LocalDateTime.now();
        //2.格式化为yyyMM
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyyMM");
        String format = now.format(timeFormatter);
        //3.获取当前用户id和要添加的分数
        Long userId = message.getUserId();
        Integer points = message.getPoints();
        //拼接key，存入的含义为某个月（某个赛季）某个用户获取积分的总和
        String key= RedisConstants.POINTS_KEY_PREFIX+format;
        log.info("保存积分到redis：{}", key);
        redisTemplate.opsForZSet().add(key, userId.toString(), points);
        log.info("保存积分到redis成功：{}", key);
    }

    //TODO 笔记积分
    private void Note(SignInMessage message, PointsRecordType type) {
    }


    private void QuestionAndAnswer(SignInMessage message, PointsRecordType type) {
        int count = getLimit(message, type);
        if (count >=4){
            throw new BizIllegalException("已达问答获取积分上限，明天再来吧！");
        }
        saveScoreToRedis(message);
        this.save(new PointsRecord().setPoints(message.getPoints()).setUserId(message.getUserId()).setType(type));

    }

    private void Learning(SignInMessage message, PointsRecordType type) {
       /* LocalDateTime now = LocalDateTime.now();
        //获取当前天的起始时间和结束时间
        LocalDateTime startTime = now.withHour(0).withMinute(0).withSecond(0);
        LocalDateTime endTime = now.withHour(23).withMinute(59).withSecond(59);
        Integer count = this.lambdaQuery().eq(PointsRecord::getUserId, message.getUserId())
                .eq(PointsRecord::getType, type)
                .between(PointsRecord::getCreateTime, startTime, endTime).count();*/
        int count = getLimit(message, type);
        if (count >=5){
            throw new BizIllegalException("已达学习获取积分上限，明天再来吧！");
        }saveScoreToRedis(message);
        this.save(new PointsRecord().setPoints(message.getPoints()).setUserId(message.getUserId()).setType(type));

    }

    private void Sign(SignInMessage message, PointsRecordType type) {
            saveScoreToRedis(message);
       //this.save(new PointsRecord().setPoints(message.getPoints()).setUserId(message.getUserId()).setType(type));
    }
    public int getLimit(SignInMessage message, PointsRecordType type){
        LocalDateTime now = LocalDateTime.now();
        //获取当前天的起始时间和结束时间
        LocalDateTime startTime = now.withHour(0).withMinute(0).withSecond(0);
        LocalDateTime endTime = now.withHour(23).withMinute(59).withSecond(59);
        return this.lambdaQuery().eq(PointsRecord::getUserId, message.getUserId())
                .eq(PointsRecord::getType, type)
                .between(PointsRecord::getCreateTime, startTime, endTime).count();
    }
}
